package com.thb.pay.core.handler;

import com.alibaba.fastjson.JSON;
import com.google.common.collect.Lists;
import com.thb.pay.core.exception.RRException;
import com.thb.pay.core.locale.LocaleMessageSourceService;
import com.thb.pay.core.utils.R;
import com.thb.pay.core.vo.ArgumentInvalidResult;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.http.converter.HttpMessageConversionException;
import org.springframework.validation.BindException;
import org.springframework.validation.BindingResult;
import org.springframework.validation.FieldError;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.ResponseStatus;
import org.springframework.web.bind.annotation.RestControllerAdvice;

import javax.servlet.http.HttpServletRequest;
import java.util.List;

/**
 * 异常处理器
 *
 * @date 2016年10月27日 下午10:16:19
 */
@Slf4j
@RestControllerAdvice
public class RRExceptionHandler {

    @Autowired
    private LocaleMessageSourceService localeMessageSourceService;

    @ResponseBody
    @ExceptionHandler(BindException.class)
    @ResponseStatus(HttpStatus.BAD_REQUEST)
    public R handleBindException(BindException ex) {
        //校验 除了 requestbody 注解方式的参数校验 对应的 bindingresult 为 BeanPropertyBindingResult @Valid /@Validated
        FieldError fieldError = ex.getBindingResult().getFieldError();
        log.error("handleBindException-必填校验异常:{}({})", fieldError.getDefaultMessage(), fieldError.getField());
        List<ArgumentInvalidResult> invalidArguments = getArgumentInvalidResults(ex.getBindingResult());

        return R.error(400, JSON.toJSONString(invalidArguments));
    }

    private List<ArgumentInvalidResult> getArgumentInvalidResults(BindingResult bindingResult) {
        //按需重新封装需要返回的错误信息
        List<ArgumentInvalidResult> invalidArguments = Lists.newArrayList();
        //解析原错误信息，封装后返回，此处返回非法的字段名称，原始值，错误信息
        for (FieldError error : bindingResult.getFieldErrors()) {
            ArgumentInvalidResult invalidArgument = new ArgumentInvalidResult();
            invalidArgument.setDefaultMessage(error.getDefaultMessage());
            invalidArgument.setField(error.getField());
            invalidArgument.setRejectedValue(error.getRejectedValue());
            invalidArguments.add(invalidArgument);
        }
        return invalidArguments;
    }

    //添加全局异常处理流程，根据需要设置需要处理的异常，本文以MethodArgumentNotValidException为例 @Valid /@Validated
    @ResponseBody
    @ExceptionHandler(value = MethodArgumentNotValidException.class)
    @ResponseStatus(HttpStatus.BAD_REQUEST)
    public R MethodArgumentNotValidHandler(HttpServletRequest request,
                                           MethodArgumentNotValidException exception) throws Exception {
        //按需重新封装需要返回的错误信息
        List<ArgumentInvalidResult> invalidArguments = getArgumentInvalidResults(exception.getBindingResult());
        log.error("MethodArgumentNotValidHandler-必填校验异常:({})", JSON.toJSONString(invalidArguments));
        return R.error(400, JSON.toJSONString(invalidArguments));
    }

    /**
     * 参数类型转换错误
     *
     * @param exception 错误
     * @return 错误信息
     */
    @ResponseBody
    @ExceptionHandler(HttpMessageConversionException.class)
    @ResponseStatus(HttpStatus.BAD_REQUEST)
    public R parameterTypeException(HttpMessageConversionException exception) {
        log.error(exception.getCause().getLocalizedMessage());
        return R.error("类型转换错误");

    }
    /**
     * 处理自定义异常
     */
    @ExceptionHandler(RRException.class)
    public R handleRRException(RRException e) {
        R result = R.builder().put("code", e.getCode()).put("msg", localeMessageSourceService.getMessage(e.getMessage(), e.getArgs(), e.getMessage())).build();
        return result;
    }


    @ExceptionHandler(Exception.class)
    public R handleException(Exception e) {
        log.error(e.getMessage(), e);
        return R.error();
    }
}
